package main

import (
	"fmt"
	"os"
)

//作业一  解析执行过程，描述过程
func Setp1() {
	s := make([]int, 5)
	fmt.Printf("切片s的本身的内存地址是:%p\n", &s)
	fmt.Printf("切片s存储的数据的地址是%p，切片内容是s=%v,切片长度是s=%d,切片的容量是s=%d\n", s, s, len(s), cap(s))
	s = append(s, 1, 3, 4)
	fmt.Printf("切片s追加元素后本身的内存地址是%p\n", &s)
	fmt.Printf("切片s的地址是%p，切片内容是s=%v,切片长度是s=%d,切片的容量是s=%d\n", s, s, len(s), cap(s))
	sss1 := make([]string, 0)
	sss1 = append(sss1, "abc", "ajkedj")
	fmt.Println(sss1)
}

//作业一解答: 定义一个长度为5，默认容量也为5的整型切片,切片s的初始值是[0,0,0,0,0],采用append函数给切片中追加1，3，4三个数据后，此时，切片s存储的数据为[0,0,0,0,0,1,3,4]
//在追加完数据后，切片s的长度是8，容量是10.

//*作业二 解析执行过程，描述过程
func Setp2() {
	p1 := 1   //p1的地址是0x01
	p2 := &p1 //p2的地址是0x02,且p2存储的数据地址是p1的地址
	*p2++     //*代表取值，因此 p2=0x01，p1=2 p1与p2是值拷贝
	fmt.Println(p1)
	fmt.Println(p2)
}

//***作业三 解析执行过程，描述过程
func Setp3() {
	a := [3]int{0, 1, 2}                   //a是一个长度为3,容量也为3的数组，假设数组a的地址是0xa0，且数组是值类型
	fmt.Printf("索引为1的数组a的地址是:%p\n", &a[1]) //0x98
	s := a[1:2]                            //s是从数组a中衍生出的切片，且切片的数据为[1],长度是1，容量是2,假设切片s的地址是0x98，但是所存储的底层数据地址是数组a的地址，因为它存储的是索引为1的数组a的地址，且切片s是引用类型
	fmt.Printf("切片s的地址是:%p\n", s)
	s[0] = 11                             //修改切片s索引为0的元素的值为11，因为底层数据是数组a，且切片s保存的数据内存地址也是a的地址，因此修改切片s时，数组a[1]的值也变化为11
	s = append(s, 12)                     //[11,12]  因为原切片s的容量是2，此时增加一个数据后，还是符合原切片s的容量，因此不会产生新的切片s，所以切片s的地址不变，数组a[2]变为12
	fmt.Printf("第一次增加数据后s的内存地址是:%p\n", s) //0x98
	s = append(s, 13)                     //[11,12,13]
	fmt.Printf("第二次增加数据后s的内存地址是:%p\n", s)
	s[0] = 21      //[21,12,13] 此时，因此上一次增加数据，导致切片扩容，产生了新的切片s，新切片s的底层数据地址不再是之前数组a的地址，因此数组a的数据为[0,11,12]
	fmt.Println(a) //[0,11,12]
	fmt.Println(s) //[21,12,13]
}

//作业四  切片的反转
func Setp4() {
	s := []int{2, 1, 3, 5, 4}

	//v := []int{}
	//for i := range s {
	//	v = append(v, s[len(s)-i-1])
	//}
	//fmt.Println(v)
	//冒泡排序: 将相邻的两个元素进行比较,并交换位置进行重新排序 s[j] < s[j+1] 从大到小排序  s[j] > s[j+1] 从小到大排序
	for i := 1; i < len(s); i++ { //第一轮
		for j := 0; j < len(s)-i; j++ {
			if s[j] > s[j+1] { //第一轮 2 >1  第二轮 2>3 不成立,退出第二次循环  第三轮 3>5 不成立 退出第二层循环  第四轮 5>4 条件成立 进入第二层循环
				s[j], s[j+1] = s[j+1], s[j]
				fmt.Println("冒泡排序:", s)
			}
		}
	}
	fmt.Println("冒泡排序:", s)
}

//作业五 解析执行过程  描述过程
func Step5() {
	var a = [5]int{1, 2, 3, 4, 5} //定义一个数组a，长度为5，容量也是5
	var r [5]int                  //定义一个数组r，默认数组的值是[0,0,0,0,0],长度5，容量5
	for i, v := range &a {        //此处通过循环数组a的地址(相当于此时是一个硬链接，即引用类型--浅拷贝),当索引等于0时，修改索引为1和2的数组对应的值
		if i == 0 {
			a[1] = 12 //[1,12,3,4,5]
			a[2] = 13 //[1,12,13,4,5]
		}
		r[i] = v //[1:12,2:13,3:4,4:5] 因为循环的是a数组的地址
	}
	fmt.Println("r= ", r) //[1,12,13,4,5]
	fmt.Println("a= ", a) //[1,12,13,4,5]
}

// 作业六  说说你对new()与make的认识
//make 的作用是初始化内置的数据结构，也就是我们在前面提到的切片、哈希表和 Channel；
//new 的作用是根据传入的类型分配一片内存空间并返回指向这片内存空间的指针；不会初始化内存，只会将内存置零
//作业七 解析执行过程
func Step7() {
	arr := [4]int{1, 2, 3, 4} //arr是一个长度为4，容量为4的数组，假设数组的地址是0x10
	fmt.Printf("数组a的地址是:%p\n", &arr)
	s1 := arr[0:2] //s1是从数组arr衍生出的切片，切片s1的长度是2，容量是4，地址是0x20,但保存的索引为1的切片的值的地址与数组arr[1]的地址相同，所以s1保存的数据地址是0x10 [1,2]
	fmt.Printf("切片s1的内存地址是:%p\n", s1)
	s2 := s1 //切片s2的长度是2，容量是4 [1,2]
	fmt.Printf("切片s2的内存地址是:%p\n", s2)
	s3 := append(append(append(s1, 1), 2), 3)
	fmt.Printf("切片s3的内存地址是:%p\n", s3)
	//第一步
	//	s3:=append(append(s1,2),3) // append(append(s1[1,2,1],2),3)  此时还没有超出底层切片s1的容量，所以底层数据地址还是s1的地址,s1[1,2,1],因为s1的底层数据地址是数组arr的地址，因此arr[1，2，1，4]
	//第二步
	// s3:=append(s1,3) //s1[1,2,1,2] s2[1,2,1,2]   append([1,2,1,2],3)--> s3=[1,2,1,2,3] 此时已经超出了底层s1的容量，因此会重新创建一个内存地址空间，即底层的数据内存地址不再是s1的地址了，因为s1的底层数据地址是数组arr的地址，因此arr【1，2，1，2]
	//第三步
	// s3[1,2,1,2,3] 长度为5，容量为8
	s1[0] = 1000
	fmt.Println(s1)  //[1000,2]
	fmt.Println(s2)  //[1000,2]
	fmt.Println(s3)  //[1,2,1,2,3]
	fmt.Println(arr) //[1000,2,1,2]
}

//作业八 基于切片实现客户关系管理系统(客户增删改查)。客户信息包括姓名、年龄、职业
// 数据结构采用以下结构
func Step8() {
	var customers [][]string
	for {
		fmt.Println(`
		 客户管理系统
		1、增加客户信息
		2、查找客户信息
		3、修改客户信息
		4、删除客户信息
		5、退出系统
		`)
		var choice int
		fmt.Println("您输入的选择是: ")
		fmt.Scan(&choice)
		switch choice {
		case 1:
			var name, age, work string
			fmt.Println("输入客户姓名:")
			fmt.Scan(&name)
			fmt.Println("输入客户年龄:")
			fmt.Scan(&age)
			fmt.Println("输入客户职位:")
			fmt.Scan(&work)
			customers = append(customers, []string{name, age, work})
			fmt.Println("增加信息成功")
		case 2:
			for index, value := range customers {
				fmt.Printf(" %d 姓名:%s 年龄:%s 职位:%s\n", index, value[0], value[1], value[2])
			}
		case 3:
			fmt.Println("请输入要修改学生的索引:")
			var index int
			fmt.Scan(&index)
			if index >= 0 && index < len(customers) {
				var name, age, work string
				fmt.Println("请输入新的姓名:")
				fmt.Scan(&name)
				fmt.Println("请输入新的年龄:")
				fmt.Scan(&age)
				fmt.Println("请输入新的职位:")
				fmt.Scan(&work)
				customers[index][0] = name
				customers[index][1] = age
				customers[index][2] = work
				fmt.Printf("成功修改索引为%d的信息\n", index)
			} else {
				fmt.Printf("修改索引为%d的信息失败\n", index)
			}
		case 4:
			fmt.Println("请输入要删除的学生的索引:")
			var index int
			fmt.Scan(&index)
			if index >= 0 && index < len(customers) {
				customers = append(customers[:index], customers[index+1:]...)
				fmt.Printf("删除索引%d成功\n", index)
			} else {
				fmt.Printf("删除索引%d失败\n", index)
			}
		case 5:
			os.Exit(1)
		default:
			fmt.Println("输入有误~~~")
		}
	}
}
func main() {
	Setp1()
	Setp2()
	Setp3()
	Setp4()
	Step5()
	Step7()
	Step8()
}
